package com.copm.ifm.base.basic;

import cn.hutool.core.util.ReflectUtil;
import com.copm.ifm.base.basic.enums.ResponseCodeEnum;
import com.copm.ifm.base.basic.exception.ServiceException;
import com.copm.ifm.base.basic.util.RedisServerUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 统一接口返回值
 *
 * @author zzf
 * @date 2020/6/29 16:32
 */
@Getter
@Setter
@ApiModel("统一接口返回对象")
public class ServiceResponse<T> implements Serializable {

    @ApiModelProperty("数据")
    private T data;

    @ApiModelProperty("状态编号")
    private Integer code;

    @ApiModelProperty("消息内容")
    private String message;

    /**
     * by和byName开发约定好不能随意修改
     * 注：否则就会获取不上，并且在返回VO的类上不能以继承BaseVO的方式，
     * 这样会获取不道creatBy和updateBy，必须在该类上添加上
     */
    private final static String By = "By";
    private final static String ByName = "ByName";

    /**
     * \@JsonInclude(JsonInclude.Include.NON_NULL) 表示为null则不序列化
     */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @ApiModelProperty("报错信息")
    private String error;

    public ServiceResponse(T data, Integer code, String message) {
        super();
        this.setData(data);
        this.setCode(code);
        this.setMessage(message);
        getNameVO(data);
    }

    public ServiceResponse(Integer code, String message) {
        super();
        this.setCode(code);
        this.setMessage(message);
    }

    public ServiceResponse(Exception e) {

        this.setCode(ResponseCodeEnum.FAIL.getCode());
        this.setMessage(ResponseCodeEnum.FAIL.getDesc());
        this.setError(getExceptionTrace(e));
    }

    public static String getExceptionTrace(Exception e) {
        //输出栈信息
        StringBuilder buffer = new StringBuilder(e.getClass().getSimpleName()).append("：");
        String message = e.getMessage();
        if (message != null) {
            buffer.append(message).append(":");
        }
        for (StackTraceElement element : e.getStackTrace()) {
            String className = element.getClassName();
            if (className.contains("com.copm")) {
                buffer.append(className).append("（")
                        .append(element.getMethodName()).append("：")
                        .append(element.getLineNumber()).append("）。").append(System.lineSeparator());
            }
        }
        return buffer.toString();
    }

    public ServiceResponse(ServiceException e) {
        super();
        this.setCode(e.getCode() == null ? ResponseCodeEnum.FAIL.getCode() : e.getCode());
        this.setMessage(e.getMessage());
    }

    public ServiceResponse(T data, ResponseCodeEnum exceptionEnum) {
        this.message = exceptionEnum.getDesc();
        this.code = exceptionEnum.getCode();
        this.data = data;
        if (!StringUtils.isEmpty(data)) {
            getNameVO(data);
        }
    }

    private void getNameVO(Object entity) {
        if (entity instanceof Collection) {
            // 增加集合适配
            ((Collection<?>) entity).forEach(this::doFilter);
            return;
        }
        if (entity instanceof NameTag) {
            doFilter(entity);
        }
    }

    private void doFilter(Object entity) {
        if (entity instanceof NameTag) {
            // 获取createBy updateBy sendBy 之类的字段
            List<Field> userIdFields = Stream.of(entity.getClass().getDeclaredFields())
                    .filter(s -> s.getName().endsWith(By)).collect(Collectors.toList());

            // 判断是否存对应 createByName updateByName
            List<Field> userNameFields = Stream.of(entity.getClass().getDeclaredFields())
                    .filter(s -> s.getName().endsWith(ByName)).collect(Collectors.toList());

            for (Field userNameField : userNameFields) {
                for (Field userIdField : userIdFields) {
                    boolean b = userNameField.getName().startsWith(userIdField.getName());
                    if (b) {
                        //獲取用戶id
                        Object userId = ReflectUtil.getFieldValue(entity, userIdField);
                        // 根據id查询name
                        String userName;
                        if (StringUtils.isEmpty(userId)) {
                            userName = null;
                        } else {
                            userName = RedisServerUtils.getNameById(Long.valueOf(userId.toString()));
                        }
                        // 插入
                        ReflectUtil.setFieldValue(entity, userNameField, userName == null ? "无" : userName);
                    }
                }
            }
        }
    }


    public ServiceResponse(ResponseCodeEnum codeCodeEnum) {
        this.setCode(codeCodeEnum.getCode());
        this.setMessage(codeCodeEnum.getDesc());
    }


    public ServiceResponse(ResponseCodeEnum codeCodeEnum, String errorMsg) {
        this.setCode(codeCodeEnum.getCode());
        this.setMessage(codeCodeEnum.getDesc());
        this.setError(errorMsg);
    }

    public ServiceResponse() {
    }

    /**
     * 判断是否成功
     */
    public boolean succeeded() {
        return ResponseCodeEnum.SUCCESS.getCode().equals(this.code);
    }
}
